package com.untilov.gb;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;

import com.alsutton.xmlparser.XMLParser;
import com.untilov.gb.model.FeedItem;
import com.untilov.gb.xml.listener.GBookmarksSAXListener;

/**
 * Converts xml input stream to collection of Value Objects representing feeds.
 * 
 * @author iuntilov
 * 
 */
public class FeedsBuilder {

    /**
     * Collection of feeds
     */
    private Vector feeds;
    
    private Vector categoriesSortedByName;
    
    private Hashtable feedsByCategories;

    /**
     * Converts stream of data to collection of objects.
     * 
     * @param xml
     *            input data stream
     * @return collection of objects
     * @throws IOException
     */
    public Vector createFeeds(InputStream xml) throws IOException {
        this.feeds = new Vector();
        XMLParser parser = new XMLParser(new GBookmarksSAXListener(this.feeds));
        parser.convertAllTagNamesToLowerCase(true);
        parser.parse(new InputStreamReader(xml, "UTF-8"));
        return this.feeds;
    }
    
    /**
     * Sorts categories by name.
     * 
     * @param feeds
     * @return
     */
    public Vector sortCategoriesByName() {
        if (feeds == null) {
            return null;
        }
        categoriesSortedByName = getCategoriesWithOutDuplicates();
        // sort
        int size = categoriesSortedByName.size();
        for (int i = 0; i < size; i++) {
            String curr = (String) categoriesSortedByName.elementAt(i);
            for (int j = i; j < size; j++) {
                String next = (String) categoriesSortedByName.elementAt(j);
                // if current more than next, switch places
                if (curr.compareTo(next) > 0) {
                    categoriesSortedByName.setElementAt(curr, categoriesSortedByName.indexOf(next));
                    categoriesSortedByName.setElementAt(next, categoriesSortedByName.indexOf(curr));                    
                    curr = next;
                }
            }
        }        
        return categoriesSortedByName;
    }
    
    /**
     * Returns collection of categories without duplicates.
     * 
     * @param feeds
     * @return
     */
    Vector getCategoriesWithOutDuplicates() {
        Vector result = new Vector();
        int numOfFeeds = feeds.size();
        for (int i = 0; i < numOfFeeds ; i++) {
            String category = ((FeedItem) feeds.elementAt(i)).getCategory();
            if (!result.contains(category)) {
                result.addElement(category);
            }
        }
        return result;
    }

    /**
     * Add FeedItems to hashtable, where key is category of item and value is Vector
     * that contains all feeditems with the equal category.
     * 
     * @return hastable -> (category => Vector<FeedItem>)
     */
    public Hashtable groupByCategories () {
        if (feeds == null) {
            return null;
        }
        feedsByCategories = new Hashtable();
        Enumeration feedsEnumerator = feeds.elements();
        while (feedsEnumerator.hasMoreElements()) {
            FeedItem item = (FeedItem) feedsEnumerator.nextElement();
            // if table doesn't contain such key, initialize it with empty Vector
            // and add this value
            if (!feedsByCategories.containsKey(item.getCategory())) {
                Vector categoryContent = new Vector();
                categoryContent.addElement(item);
                feedsByCategories.put(item.getCategory(), categoryContent);                
            } else { // we alredy have smt for this key
                ((Vector) feedsByCategories.get(item.getCategory())).addElement(item);
            }
        }        
        return feedsByCategories;
    }

    public Vector getCategoriesSortedByName() {
        return categoriesSortedByName;
    }

    void setCategoriesSortedByName(Vector categoriesSortedByName) {
        this.categoriesSortedByName = categoriesSortedByName;
    }

    public Vector getFeeds() {
        return feeds;
    }

    void setFeeds(Vector feeds) {
        this.feeds = feeds;
    }

    public Hashtable getFeedsByCategories() {
        return feedsByCategories;
    }

    void setFeedsByCategories(Hashtable feedsByCategories) {
        this.feedsByCategories = feedsByCategories;
    }
}